﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using FRW.Common.Extensions;

namespace Money.Interface
{
    public partial class DateRange : UserControl
    {
        private class StandardDateRange
        {
            public string RangeName;
            public TimeSpan Span;
            public DateTime StartDate;
            public DateTime EndDate;
            public bool Lock = false;
        }

        private int _daysInRange = 0;

        private List<StandardDateRange> _standardDates = new List<StandardDateRange>();

        public delegate void DateChangedEventHandler(object sender, DateChangedEventArgs e);
        public event DateChangedEventHandler DateChanged;

        private TimeSpan _lockSpan;
        
        private DateTime _startDate;

        private DateTime _maxDate;

        private bool _updating = false;

        public DateTime MaxDate
        {
            get { return _maxDate; }
            set 
            { 
                _maxDate = value;
                ConfigureControls();
            }
        }

        private DateTime _minDate;

        public DateTime MinDate
        {
            get { return _minDate; }
            set 
            { 
                _minDate = value;
                ConfigureControls();
            }
        }

        public DateTime StartDate
        {
            get { return _startDate; }
            set { _startDate = value; }
        }
        private DateTime _endDate;

        public DateTime EndDate
        {
            get { return _endDate; }
            set { _endDate = value; }
        }

        public DateRange()
        {
            InitializeComponent();

            PopulateStandardDates();

            foreach (StandardDateRange dateRange in _standardDates)
            {
                cbStandardDate.Items.Add(dateRange.RangeName);
            }
        }

        private void PopulateStandardDates()
        {
            DateTime thisMonthStart = DateTime.Now.StartOfMonth();
            DateTime thisMonthEnd = thisMonthStart.AddMonths(1).Subtract(new TimeSpan(1,0,0,0));
            DateTime lastMonthStart = new DateTime(thisMonthStart.Year, thisMonthStart.Month - 1, thisMonthStart.Day);
            DateTime lastMonthEnd = lastMonthStart.AddMonths(1).Subtract(new TimeSpan(1, 0, 0, 0));

            _standardDates.Add(new StandardDateRange() { RangeName = "This Month", StartDate = thisMonthStart, EndDate = thisMonthEnd });
            _standardDates.Add(new StandardDateRange() { RangeName = "Last Month", StartDate = lastMonthStart, EndDate = lastMonthEnd });
            _standardDates.Add(new StandardDateRange() { RangeName = "1 Month", Span = new TimeSpan(28, 0, 0, 0) });
            _standardDates.Add(new StandardDateRange() { RangeName = "1 Week", Span = new TimeSpan(7, 0, 0, 0), Lock = true });
            _standardDates.Add(new StandardDateRange() { RangeName = "1 Year", Span = new TimeSpan(365, 0, 0, 0), Lock = true });
        }

        private void ConfigureControls()
        {
            if (_maxDate.Year < 1800 || _minDate.Year < 1800)
            {
                tbEndDate.Enabled = false;
                tbStartDate.Enabled = false;
            }
            else
            {
                CalculateTimeSpan();

                dpEndDate.MaxDate = dpStartDate.MaxDate = _maxDate;
                dpEndDate.MinDate = dpStartDate.MinDate = _minDate;

                tbEndDate.Enabled = true;
                tbStartDate.Enabled = true;
                tbEndDate.Maximum = tbStartDate.Maximum = _daysInRange;

                // we dont set any of the values until the ranges are set as required
                dpStartDate.Value = _minDate;
                dpEndDate.Value = _maxDate;
                tbEndDate.Value = _daysInRange;
            }
        }


        private void CalculateTimeSpan()
        {
            TimeSpan dateRange = _maxDate - _minDate;
            _daysInRange = dateRange.Days;
        }

        private void OnDateChanged()
        {
            DateChangedEventArgs eventArgs = new DateChangedEventArgs();

            // TODO we should maybe update these in the event handlers within the control so latest value is always available?
            _startDate = dpStartDate.Value;
            _endDate = dpEndDate.Value;

            eventArgs.StartDate = _startDate;
            eventArgs.EndDate = _endDate;

            if (DateChanged != null)
            {
                DateChanged(this, eventArgs);
            }
        }

        public void RaiseDateChangedEvent()
        {
            OnDateChanged();
        }

        private void cbStandardDate_SelectionChangeCommitted(object sender, EventArgs e)
        {
            StandardDateRange dateRange = _standardDates.FindLast(dr => dr.RangeName.Equals(cbStandardDate.Text));

            cbLocked.Checked = dateRange.Lock;
            _lockSpan = dateRange.Span;

            if (dateRange.EndDate.Year > 1800 && dateRange.StartDate.Year > 1800)
            {
                SetDatePickerDate(dpStartDate, dateRange.StartDate);
                SetDatePickerDate(dpEndDate, dateRange.EndDate);
            }
            else if (dateRange.EndDate.Year > 1800)
            {
                SetDatePickerDate(dpEndDate, dateRange.EndDate);

                if (dateRange.Span != null && dateRange.Span.Days > 0)
                {
                    SetDatePickerDate(dpStartDate, dpEndDate.Value.Subtract(dateRange.Span));
                }
            }
            else if (dateRange.StartDate.Year > 1800)
            {
                SetDatePickerDate(dpStartDate, dateRange.StartDate);
                if (dateRange.Span != null && dateRange.Span.Days > 0)
                {
                    SetDatePickerDate(dpEndDate, dpEndDate.Value.Add(dateRange.Span));
                }
            }
            else
            {
                if (dateRange.Span != null && dateRange.Span.Days > 0)
                {
                    SetDatePickerDate(dpEndDate, dpStartDate.Value.Add(dateRange.Span));
                }
            }
        }

        private void tbStartDate_MouseUp(object sender, MouseEventArgs e)
        {
            OnDateChanged();
        }

        private void tbStartDate_ValueChanged(object sender, EventArgs e)
        {
            if (!_updating)
            {
                _updating = true;
                SetDatePickerDate(dpStartDate, SliderToDate(tbStartDate.Value));

                if (tbEndDate.Value < tbStartDate.Value)
                {
                    SetTrackBarDate(tbEndDate, dpStartDate.Value);
                    SetDatePickerDate(dpEndDate, dpStartDate.Value);
                }

                if (cbLocked.Checked)
                {
                    SetDatePickerDate(dpEndDate, dpStartDate.Value.Add(_lockSpan));
                    SetTrackBarDate(tbEndDate, dpEndDate.Value);
                }

                if (cbLive.Checked == true)
                {
                    _startDate = SliderToDate(tbStartDate.Value);
                    OnDateChanged();
                }
                _updating = false;
            }
        }

        private void SetDatePickerDate(DateTimePicker picker, DateTime date)
        {
            if (date < picker.MinDate)
            {
                picker.Value = picker.MinDate;
            }
            else if (date > picker.MaxDate)
            {
                picker.Value = picker.MaxDate;
            }
            else
            {
                picker.Value = date;
            }
        }

        private void SetTrackBarDate(TrackBar bar, DateTime date)
        {
            int newValue = DateToSlider(date);

            if (newValue < bar.Minimum)
            {
                bar.Value = bar.Minimum;
            }
            else if (newValue > bar.Maximum)
            {
                bar.Value = bar.Maximum;
            }
            else
            {
                bar.Value = newValue;
            }
        }

        private DateTime SliderToDate(int sliderValue)
        {
            DateTime date;

            date = _minDate.AddDays(sliderValue);

            return date;
        }

        private int DateToSlider(DateTime date)
        {
            int sliderValue;

            TimeSpan timeSpan = date - _minDate;

            sliderValue = timeSpan.Days;

            return sliderValue;
        }

        private void dpStartDate_ValueChanged(object sender, EventArgs e)
        {
            if (!_updating)
            {
                _updating = true;

                SetTrackBarDate(tbStartDate, dpStartDate.Value);

                if (cbLocked.Checked)
                {
                    SetDatePickerDate(dpEndDate, dpStartDate.Value.Add(_lockSpan));
                    SetTrackBarDate(tbEndDate, dpEndDate.Value);
                }

                _updating = false;

                OnDateChanged();
            }
        }

        private void dpEndDate_ValueChanged(object sender, EventArgs e)
        {
            if (!_updating)
            {
                _updating = true;
                
                SetTrackBarDate(tbEndDate, dpEndDate.Value);

                if (cbLocked.Checked)
                {
                    SetDatePickerDate(dpStartDate, dpEndDate.Value.Subtract(_lockSpan));
                    SetTrackBarDate(tbStartDate, dpStartDate.Value);
                }

                _updating = false;

                OnDateChanged();
            }
        }

        private void tbEndDate_ValueChanged(object sender, EventArgs e)
        {
            if (!_updating)
            {
                _updating = true;

                SetDatePickerDate(dpEndDate, SliderToDate(tbEndDate.Value));

                if (tbEndDate.Value < tbStartDate.Value)
                {
                    SetTrackBarDate(tbStartDate, dpEndDate.Value);
                    SetDatePickerDate(dpStartDate, dpEndDate.Value);
                }

                if (cbLocked.Checked)
                {
                    SetDatePickerDate(dpStartDate, dpEndDate.Value.Subtract(_lockSpan));
                    SetTrackBarDate(tbStartDate, dpStartDate.Value);
                }

                if (cbLive.Checked)
                {
                    OnDateChanged();
                }

                _updating = false;
            }
        }

        private void tbEndDate_MouseUp(object sender, MouseEventArgs e)
        {
            OnDateChanged();
        }

        private void cbLocked_CheckedChanged(object sender, EventArgs e)
        {
            if (cbLocked.Checked)
            {
                _lockSpan = dpEndDate.Value - dpStartDate.Value;
            }
        }
    }

    public class DateChangedEventArgs : EventArgs
    {
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
    }


}
